package org.cupk2.zhzm.service.impl;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.cupk2.base.db.CupkDbFields;
import org.cupk2.base.domain.CupkUserContextLoader;
import org.cupk2.base.event.enums.F2EActionT;
import org.cupk2.base.event.enums.F2EObjectT;
import org.cupk2.base.event.face.Cupk2Events;
import org.cupk2.base.exception.CupkExceptionUtils;
import org.cupk2.files.domain.ResourceFile;
import org.cupk2.files.domain.ex.CupkFilePath;
import org.cupk2.files.service.ResourceFileServiceInter;
import org.cupk2.files.utils.Cupk2RegisteTypeEnum;
import org.cupk2.zhzm.dao.ZhzmKnowDao;
import org.cupk2.zhzm.dao.ZhzmKnowFileDao;
import org.cupk2.zhzm.dao.ZhzmKnowTagDao;
import org.cupk2.zhzm.dao.ZhzmKnowVersionDao;
import org.cupk2.zhzm.dto.web.IndexTagsDto;
import org.cupk2.zhzm.dto.web.WebKnowDto;
import org.cupk2.zhzm.domain.ZhzmKnow;
import org.cupk2.zhzm.domain.ZhzmKnowFile;
import org.cupk2.zhzm.domain.ZhzmKnowTag;
import org.cupk2.zhzm.domain.ZhzmKnowVersion;
import org.cupk2.zhzm.dto.web.WebTagDto;
import org.cupk2.zhzm.enums.CupkKnowFileMarkEnum;
import org.cupk2.zhzm.enums.KnowFileTypeEnum;
import org.cupk2.zhzm.enums.KnowModelEnum;
import org.cupk2.zhzm.enums.KnowStateEnum;
import org.cupk2.zhzm.service.ZhzmKnowServiceInter;
import org.cupk2.zhzm.utils.ZhzmFileMarkUtils;
import org.cupk2.tools.db.DataQuery;
import org.cupk2.tools.db.DataResult;
import org.cupk2.tools.db.commons.DBRule;
import org.cupk2.tools.db.commons.DBRuleList;
import org.cupk2.tools.files.Cupk2FileUtils;
import org.cupk2.tools.i18n.I18n;
import org.cupk2.tools.i18n.string.CupkStringUtils;
import org.cupk2.tools.time.CupkTimeTool;
import org.cupk2.tools.web.Cupk2HtmlUtils;
import org.cupk2.tools.web.Cupk2HtmlUtilsHandleInter;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.File;
import java.io.IOException;
import java.util.*;

/**知识 
 * @author cbtg自动生成  2025-2-4 12:13:51 
 */
@Service
@Slf4j
public class ZhzmKnowServiceImpl implements ZhzmKnowServiceInter {
    @Autowired
    private ZhzmKnowVersionDao zhzmKnowVersionDao;
    @Autowired
    private ZhzmKnowFileDao zhzmKnowFileDao;
    @Autowired
    private ZhzmKnowDao zhzmKnowDao;
    @Autowired
    private ResourceFileServiceInter resourceFileServiceImpl;
    @Autowired
    private ZhzmKnowTagDao zhzmKnowTagDao;
    private static final String KNOW_MAIN_DOC_FILE_HTML_EXNAME = ".html";


    @Transactional
    @Override
    public ZhzmKnow insertZhzmKnowEntity(ZhzmKnow zhzmKnow) {
        CupkDbFields.initInsertBean(zhzmKnow, CupkUserContextLoader.getCurrentUser());

        zhzmKnowDao.insert(zhzmKnow);


        return zhzmKnow;
    }

    @Transactional
    @Override
    public ZhzmKnow editZhzmKnowEntity(ZhzmKnow zhzmKnow) {
        ZhzmKnow saveZhzmKnow = getZhzmKnowById(zhzmKnow.getId());
        CupkExceptionUtils.throwNullEx(saveZhzmKnow, I18n.msg("知识不存在:?", zhzmKnow.getId()));
        saveZhzmKnow.setId(zhzmKnow.getId());
        saveZhzmKnow.setTitle(zhzmKnow.getTitle());
        saveZhzmKnow.setDocdescribe(zhzmKnow.getDocdescribe());
        saveZhzmKnow.setKnowmodel(zhzmKnow.getKnowmodel());
        saveZhzmKnow.setAuthor(zhzmKnow.getAuthor());
        saveZhzmKnow.setPubtime(zhzmKnow.getPubtime());
        saveZhzmKnow.setSource(zhzmKnow.getSource());
        saveZhzmKnow.setState(zhzmKnow.getState());
        saveZhzmKnow.setCtime(zhzmKnow.getCtime());
        saveZhzmKnow.setEtime(zhzmKnow.getEtime());
        saveZhzmKnow.setCusername(zhzmKnow.getCusername());
        saveZhzmKnow.setCuserkey(zhzmKnow.getCuserkey());
        saveZhzmKnow.setEusername(zhzmKnow.getEusername());
        saveZhzmKnow.setEuserkey(zhzmKnow.getEuserkey());
        saveZhzmKnow.setPcontent(zhzmKnow.getPcontent());
        saveZhzmKnow.setRuninfoid(zhzmKnow.getRuninfoid());
        saveZhzmKnow.setSyncid(zhzmKnow.getSyncid());
        saveZhzmKnow.setVersionid(zhzmKnow.getVersionid());
        saveZhzmKnow.setSno(zhzmKnow.getSno());
        saveZhzmKnow.setValiditys(zhzmKnow.getValiditys());
        saveZhzmKnow.setValiditye(zhzmKnow.getValiditye());
         
        CupkDbFields.initUpdateBean(saveZhzmKnow, CupkUserContextLoader.getCurrentUser());
        zhzmKnowDao.update(saveZhzmKnow);
        return saveZhzmKnow;
    }

    @Transactional
    @Override
    public ZhzmKnow getZhzmKnowById(String id) {
        return zhzmKnowDao.findById(id);
    }

    @Override
    public List<ZhzmKnow> getZhzmKnows(DataQuery query) {
        return zhzmKnowDao.queryData(query.setCount(false)).getData(ZhzmKnow.class);
    }



    @Transactional
    @Override
    public DataResult searchZhzmKnow(DataQuery query) {
        DataResult result = zhzmKnowDao.queryData(query);
        return result;
    }

    @Override
    public int getZhzmKnowNum(DataQuery query) {
        return zhzmKnowDao.countData(query);
    }


    @Transactional
    @Override
    public void delZhzmKnow(String id) {

        zhzmKnowVersionDao.delete(DBRuleList.getInstance().add(new DBRule("KNOWID", id, "=")).toList());

        zhzmKnowTagDao.delete(DBRuleList.getInstance().add(new DBRule("KNOWID", id, "=")).toList());

        List<ZhzmKnowFile> kfiles = zhzmKnowFileDao.find(DBRuleList.getInstance().add(new DBRule("KNOWID", id, "=")).toList());
        for (ZhzmKnowFile kfile : kfiles) {
            resourceFileServiceImpl.cancel(kfile.getFileid(), Cupk2RegisteTypeEnum.KNOW, id);
            zhzmKnowFileDao.deleteById(kfile.getId());
        }

        zhzmKnowDao.deleteById(id);

        Cupk2Events.emit(F2EObjectT.KNOW, id, F2EActionT.DELETE);
    }
    
    @Override
    public int getNum(DataQuery query) {
        return  zhzmKnowDao.countData(query);
    }


    /**
     * 从html中提取知识附件
     *
     * @return
     */
    private List<ZhzmKnowFile> getFilesByHtml(Document doc) {
        List<ZhzmKnowFile> sfiles = new ArrayList<>();
        {
            Cupk2HtmlUtils.getAttrs(doc, "img", "src", new Cupk2HtmlUtilsHandleInter() {
                @Override
                public void handle(Element node, String url) {
                    String id = CupkStringUtils.getFileIdByUrl(url);
                    if (StringUtils.isNotBlank(id)) {
                        sfiles.add(new ZhzmKnowFile(id, KnowFileTypeEnum.KNOW_IMG));
                        node.attr("src", ZhzmFileMarkUtils.CUPK2_BASEPATH_FLAG + "api/files/download/" + id);
                    }
                }
            });
        }

        {
            Cupk2HtmlUtils.getAttrs(doc, "video", "src", new Cupk2HtmlUtilsHandleInter() {
                @Override
                public void handle(Element node, String url) {
                    String id = CupkStringUtils.getFileIdByUrl(url);
                    if (StringUtils.isNotBlank(id)) {
                        sfiles.add(new ZhzmKnowFile(id, KnowFileTypeEnum.KNOW_MEDIA));
                        node.attr("src", ZhzmFileMarkUtils.CUPK2_BASEPATH_FLAG + "api/files/download/" + id);
                    }
                }
            });
        }
        {
            Cupk2HtmlUtils.getAttrs(doc, "audio", "src", new Cupk2HtmlUtilsHandleInter() {
                @Override
                public void handle(Element node, String url) {
                    String id = CupkStringUtils.getFileIdByUrl(url);
                    if (StringUtils.isNotBlank(id)) {
                        sfiles.add(new ZhzmKnowFile(id, KnowFileTypeEnum.KNOW_MEDIA));
                        node.attr("src", ZhzmFileMarkUtils.CUPK2_BASEPATH_FLAG + "api/files/download/" + id);
                    }
                }
            });
        }
        {
            Cupk2HtmlUtils.getAttrs(doc, "div", "fileid", new Cupk2HtmlUtilsHandleInter() {
                @Override
                public void handle(Element node, String id) {
                    if (StringUtils.isNotBlank(id)) {
                        sfiles.add(new ZhzmKnowFile(id, KnowFileTypeEnum.KNOW_FILE));
                    }
                }
            });
        }
        return sfiles;
    }

    @Override
    public String getKnowText(ZhzmKnow know) {
        List<ZhzmKnowFile> files = zhzmKnowFileDao.find(DBRuleList.getInstance().add(new DBRule("KNOWID", know.getId(), "=")).add(new DBRule("TYPE", KnowFileTypeEnum.MAIN_DOC.getKey(), "=")).add(new DBRule("VERSIONID", know.getVersionid(), "=")).toList());
        if (files.size() > 0) {
            CupkFilePath filePath = resourceFileServiceImpl.getFilePath(resourceFileServiceImpl.getResourceFileById(files.get(0).getFileid()));
            try {
                String text = Cupk2FileUtils.readText(filePath.getFile());
                return text;
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
        return "";
    }

    @Override
    public String getKnowHtml(ZhzmKnow know) {
        String text = getKnowText(know);
        Document htmldoc = Jsoup.parse(text);
        Elements videos = htmldoc.getElementsByTag("video");
        for (Element video : videos) {
            video.attr("controls", "true");
        }
        return htmldoc.html();
    }

    /**
     * 创建一个文档附件（保存知识主文档）
     *
     * @param title
     * @param html
     * @return
     */
    private ResourceFile creatKnowFile(String title, String html) {
        ResourceFile rfile = resourceFileServiceImpl.saveFile(title + KNOW_MAIN_DOC_FILE_HTML_EXNAME, html);
        return rfile;
    }

    private ZhzmKnowVersion creatVersion(String title, String knowid) {
        ZhzmKnowVersion version = new ZhzmKnowVersion();
        CupkDbFields.initInsertBean(version, CupkUserContextLoader.getCurrentUser());
        if (StringUtils.isBlank(knowid)) {
            version.setKnowid("NONE");
        } else {
            version.setKnowid(knowid);
        }
        version.setState("2");
        version.setTitle(title);
        zhzmKnowVersionDao.insert(version);
        return version;
    }

    private void bindTags(ZhzmKnow know, List<WebTagDto> tags) {
        zhzmKnowTagDao.delete(DBRuleList.getInstance().add(new DBRule("KNOWID", know.getId(), "=")).toList());
        for (WebTagDto wtag : tags) {
            ZhzmKnowTag tag = new ZhzmKnowTag();
            CupkDbFields.initInsertBean(tag, CupkUserContextLoader.getCurrentUser());
            tag.setNote(wtag.getName());
            tag.setKnowid(know.getId());
            tag.setTagkey(wtag.getTagkey());
            tag.setType(wtag.getType());
            tag.setTitle(wtag.getName());
            zhzmKnowTagDao.insert(tag);
        }
    }

    /**
     * 设置附件的应用标记
     *
     * @param kfile
     */
    private void initFileMark(ZhzmKnowFile kfile) {
        ResourceFile rfile = resourceFileServiceImpl.getResourceFileById(kfile.getFileid());
        if (rfile != null && Cupk2FileUtils.isImg(rfile.getExname())) {
            File file = resourceFileServiceImpl.getFile(rfile);
            if (Cupk2FileUtils.viewImg(file, rfile.getExname())) {
                String mark = kfile.getMark();
                if (mark == null) {
                    mark = CupkKnowFileMarkEnum.viewImg.getKey();
                } else {
                    mark = mark.replace(CupkKnowFileMarkEnum.viewImg.getKey(), "");
                    mark = mark + CupkKnowFileMarkEnum.viewImg.getKey();
                }
                kfile.setMark(mark);
            }
        }

        kfile.setExname(rfile.getExname());
    }

    @Transactional
    @Override
    public ZhzmKnow creatKnow(WebKnowDto webKnowDto) {
        List<ZhzmKnowFile> sfiles = new ArrayList<>();
        String html = webKnowDto.getText();
        Document doc = Jsoup.parse(html);
        sfiles.addAll(getFilesByHtml(doc));
        {//创建附件
            ResourceFile mianFile = creatKnowFile(webKnowDto.getTitle(), doc.html());
            sfiles.add(new ZhzmKnowFile(mianFile.getId(), KnowFileTypeEnum.MAIN_DOC));
        }

        ZhzmKnowVersion version = creatVersion(webKnowDto.getTitle(), null);

        ZhzmKnow know = new ZhzmKnow();
        {
            CupkDbFields.initInsertBean(know, CupkUserContextLoader.getCurrentUser());
            know.setAuthor(CupkUserContextLoader.getCurrentUser().getName());
            know.setDocdescribe(webKnowDto.getDocdescribe());
            know.setKnowmodel(KnowModelEnum.DOC_KNOW.getKey());
            know.setPubtime(CupkTimeTool.getTimeDate14());
            know.setRuninfoid("NONE");
            know.setState(KnowStateEnum.ABLE.getKey());
            know.setTitle(webKnowDto.getTitle());
            know.setSyncid(version.getId());
            know.setVersionid(version.getId());
            zhzmKnowDao.insert(know);
        }
        for (ZhzmKnowFile kfile : sfiles) {
            kfile.setVersionid(version.getId());
            kfile.setKnowid(know.getId());
            initFileMark(kfile);
            zhzmKnowFileDao.insert(kfile);
            resourceFileServiceImpl.submit(kfile.getFileid(), Cupk2RegisteTypeEnum.KNOW, know.getId());
        }

        {
            bindTags(know, webKnowDto.getTags());
        }
        version.setKnowid(know.getId());
        zhzmKnowVersionDao.update(version);

        Cupk2Events.emit(F2EObjectT.KNOW, know.getId(), F2EActionT.ADD);
        return know;
    }

    @Transactional
    @Override
    public ZhzmKnow editKnow(WebKnowDto webKnowDto) {
        List<ZhzmKnowFile> sfiles = new ArrayList<>();
        String html = webKnowDto.getText();
        Document doc = Jsoup.parse(html);
        sfiles.addAll(getFilesByHtml(doc));
        {//创建附件
            ResourceFile mianFile = creatKnowFile(webKnowDto.getTitle(), doc.html());
            sfiles.add(new ZhzmKnowFile(mianFile.getId(), KnowFileTypeEnum.MAIN_DOC));
        }

        ZhzmKnowVersion version = creatVersion(webKnowDto.getTitle(), webKnowDto.getId());

        ZhzmKnow know = zhzmKnowDao.findById(webKnowDto.getId());
        {
            CupkDbFields.initUpdateBean(know, CupkUserContextLoader.getCurrentUser());

            know.setDocdescribe(webKnowDto.getDocdescribe());




            know.setTitle(webKnowDto.getTitle());

            know.setVersionid(version.getId());
            zhzmKnowDao.update(know);
        }
        for (ZhzmKnowFile kfile : sfiles) {
            kfile.setVersionid(version.getId());
            kfile.setKnowid(know.getId());
            initFileMark(kfile);
            zhzmKnowFileDao.insert(kfile);
            resourceFileServiceImpl.submit(kfile.getFileid(), Cupk2RegisteTypeEnum.KNOW, know.getId());
        }

        {
            bindTags(know, webKnowDto.getTags());
        }

        Cupk2Events.emit(F2EObjectT.KNOW, know.getId(), F2EActionT.UPDATE);
        return know;
    }

    @Override
    public List<String> getInvalidVersionFileIds(ZhzmKnow know) {

        List<ZhzmKnowFile> skfiles = zhzmKnowFileDao.
                find(DBRuleList.getInstance().add(new DBRule("KNOWID", know.getId(), "=")).toList());
        Set<String> all = new HashSet<>();
        all.addAll(skfiles.stream().map(b -> b.getFileid()).toList());

        Set<String> version = new HashSet<>();
        version.addAll(skfiles.stream().filter(b -> (b.getVersionid().equals(know.getVersionid()))).map(b -> b.getFileid()).toList());

        all.removeAll(version);
        return all.stream().toList();
    }

    @Override
    public List<WebTagDto> getKnowTagDtos(ZhzmKnow know) {
        List<WebTagDto> dTos = new ArrayList<>();
        List<ZhzmKnowTag> tags = zhzmKnowTagDao.find(DBRuleList.getInstance().add(new DBRule("KNOWID", know.getId(), "=")).toList());
        for (ZhzmKnowTag wTag : tags) {
            WebTagDto dTo = new WebTagDto();
            dTo.setName(wTag.getTitle());
            dTo.setType(wTag.getType());
            dTo.setTagkey(wTag.getTagkey());
            dTos.add(dTo);
        }
        return dTos;
    }

    @Override
    public IndexTagsDto getKnowIndexTags(ZhzmKnow know) {
        List<WebTagDto> tags = getKnowTagDtos(know);

        StringBuffer keys = new StringBuffer();
        StringBuffer titles = new StringBuffer();
        for (WebTagDto tag : tags) {
            if (tag.getType().equals("1") || tag.getType().equals("2")) {
                keys.append("," + tag.getTagkey());
                titles.append("," + tag.getName());
            }
            if (tag.getType().equals("3")) {
                titles.append("," + tag.getName());
            }
        }
        IndexTagsDto bt = new IndexTagsDto();
        bt.setKeys(keys.toString());
        bt.setTitles(titles.toString());
        return bt;
    }

    @Override
    public List<String> getImgView(String knowid) {
        List<ZhzmKnowFile> ksfile = zhzmKnowFileDao.find(DBRuleList.getInstance().add(new DBRule("KNOWID", knowid, "=")).add(new DBRule("MARK", CupkKnowFileMarkEnum.viewImg.getKey(), "like")).toList());
        return ksfile.stream().map(node -> node.getFileid()).distinct().toList();
    }

    @Override
    public int getKnowNumByUser(String userKey) {
        return zhzmKnowDao.countData(DBRuleList.getInstance()//
                .add(new DBRule("CUSERKEY", userKey, "="))//
                .toList());
    }

    @Override
    public int getNewKnowsNum(String userKey) {
        String time14 = CupkTimeTool.getTimeDate14ForDay(-2, new Date());
        return zhzmKnowDao.countData(DBRuleList.getInstance()//
                .add(new DBRule("ETIME", time14, ">"))//
                .toList());
    }

    @Override
    public List<String> getKnowFiles(String knowid, String typekey) {
        ZhzmKnow know = getZhzmKnowById(knowid);
        DBRuleList list = DBRuleList.getInstance().add(new DBRule("KNOWID", knowid, "="))
                .add(new DBRule("VERSIONID", know.getVersionid(), "="));
        if (typekey != null) {
            list.add(new DBRule("TYPE", typekey, "="));
        }
        List<ZhzmKnowFile> kfiles = zhzmKnowFileDao.find(list.toList());
        List<String> ids = new ArrayList<>();
        for (ZhzmKnowFile kfile : kfiles) {
            ids.add(kfile.getFileid());
        }
        return ids;
    }
}
